<!--
/**
 * IntegratedViewerView - 集成查看器页面
 * 
 * 展示 js-3d-model 完整集成的示例页面,支持 Orthanc 连接
 * 基于 DicomStaticView 的成功实现,遵循八项开发荣辱观
 * 
 * @author yangzhixin
 */
-->

<template>
  <div class="integrated-viewer">
    <!-- 顶部工具栏 -->
    <div class="top-toolbar">
      <div class="toolbar-left">
        <h2 class="page-title">Cornerstone3D 集成查看器</h2>
        
        <!-- Orthanc 连接状态 -->
        <div class="connection-status">
          <span class="status-indicator" :class="{ 'connected': orthancConnected, 'disconnected': !orthancConnected }">
            {{ orthancConnected ? '🟢' : '🔴' }}
          </span>
          <span class="status-text">
            {{ orthancConnected ? 'Orthanc已连接' : 'Orthanc未连接' }}
          </span>
        </div>
      </div>

      <div class="toolbar-right">
        <!-- 初始化按钮 -->
        <q-btn
          v-if="!isInitialized"
          label="初始化"
          color="primary"
          icon="play_arrow"
          :loading="isInitializing"
          @click="handleInitialize"
        />
        <q-chip v-else color="positive" text-color="white" icon="check_circle">
          已初始化
        </q-chip>

        <!-- Orthanc 实例选择 -->
        <select 
          v-if="orthancConnected && isInitialized"
          v-model="selectedInstanceId" 
          class="instance-select"
          :disabled="loadingInstances"
          @click="onInstanceSelectClick"
        >
          <option value="">请选择DICOM实例</option>
          <optgroup v-for="study in availableStudies" :key="study.id" :label="study.label">
            <option 
              v-for="instance in study.instances" 
              :key="instance.id" 
              :value="instance.id"
            >
              {{ instance.label }}
            </option>
          </optgroup>
        </select>

        <!-- 刷新实例列表 -->
        <q-btn
          v-if="orthancConnected && isInitialized"
          icon="refresh"
          color="grey-7"
          flat
          round
          dense
          :loading="loadingInstances"
          @click="refreshInstanceList"
          title="刷新实例列表"
        >
          <q-tooltip>刷新实例列表</q-tooltip>
        </q-btn>

        <!-- 加载选中实例 -->
        <q-btn
          v-if="orthancConnected && isInitialized"
          label="加载选中实例"
          color="secondary"
          icon="image"
          :loading="loadingImage"
          :disable="!selectedInstanceId"
          @click="loadSelectedInstance"
        />

        <!-- 快速加载示例 -->
        <q-btn
          v-if="orthancConnected && isInitialized"
          label="加载预设示例"
          color="accent"
          icon="play_circle"
          :loading="loadingExample"
          @click="loadExampleFromOrthanc"
        />

        <!-- 上传本地文件 -->
        <q-btn
          v-if="isInitialized"
          label="上传本地文件"
          color="indigo"
          icon="upload_file"
          :loading="loadingLocalFile"
          @click="triggerFileSelect"
        />
        <input
          ref="fileInput"
          type="file"
          accept=".dcm,.dicom"
          style="display: none"
          @change="handleFileSelect"
        />
      </div>
    </div>

    <!-- 主内容区 -->
    <div class="main-content">
      <!-- 左侧面板 -->
      <div class="left-panel">
        <!-- Studies 列表 -->
        <study-list
          :studies="studies"
          :is-loading="isDicomLoading"
          :is-configured="isDicomConfigured"
          :error="dicomError"
          @search="handleSearchStudies"
          @load-study="handleLoadStudy"
        />
      </div>

      <!-- 中间视口区域 -->
      <div class="center-panel">
        <!-- 工具栏 -->
        <tool-bar
          v-if="currentImageIds.length > 0"
          :active-tool="activeTool"
          :enabled="isInitialized && currentImageIds.length > 0"
          @tool-select="handleToolSelect"
          @reset="handleReset"
          @clear-annotations="handleClearAnnotations"
          @export="handleExportAnnotations"
        />

        <!-- DICOM 查看器 -->
        <div 
          ref="viewportElement" 
          class="dicom-viewport"
          :class="{ 'has-image': currentImageIds.length > 0 }"
        >
          <div v-if="currentImageIds.length === 0" class="empty-viewport">
            <div class="empty-icon">📁</div>
            <div class="empty-text">请加载DICOM图像</div>
          </div>
        </div>

        <!-- 图像导航器 -->
        <image-navigator
          v-if="currentImageIds.length > 0"
          :current-index="currentImageIndex"
          :total-images="currentImageIds.length"
          :show-info="true"
          :window-width="windowLevel?.windowWidth || 0"
          :window-center="windowLevel?.windowCenter || 0"
          @change="handleImageNavigate"
          @first="handleImageFirst"
          @previous="handleImagePrevious"
          @next="handleImageNext"
          @last="handleImageLast"
        />
      </div>

      <!-- 右侧面板 -->
      <div class="right-panel">
        <!-- 标注列表 -->
        <annotation-list
          :annotations="annotations"
          :selected-annotations="selectedAnnotations"
          @select="handleSelectAnnotation"
          @delete="handleDeleteAnnotation"
          @clear-all="handleClearAnnotations"
          @export="handleExportAnnotations"
        />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useQuasar } from 'quasar';
import { useCornerstone3D } from '@/composables/useCornerstone3D';
import { useTools } from '@/composables/useTools';
import { useDICOMweb } from '@/composables/useDICOMweb';
import { useAnnotations } from '@/composables/useAnnotations';
import ToolBar from '@/components/ToolBar.vue';
import StudyList from '@/components/StudyList.vue';
import ImageNavigator from '@/components/ImageNavigator.vue';
import AnnotationList from '@/components/AnnotationList.vue';
import type { StudyInfo } from '@/composables/useDICOMweb';
import { orthancService } from '@/services/orthanc.service';
import { exampleDicomInstance } from '@/config/orthanc.config';

const $q = useQuasar();
const viewportElement = ref<HTMLElement>();
const currentRenderingEngineId = ref('integrated-viewer-engine');
const currentViewportId = ref('integrated-viewer-viewport');
const fileInput = ref<HTMLInputElement>();

// ========== Orthanc 连接状态 ==========
const orthancConnected = ref(false);
const selectedInstanceId = ref('');
const availableStudies = ref<any[]>([]);
const availableInstances = ref<any[]>([]);
const loadingInstances = ref(false);
const loadingImage = ref(false);
const loadingExample = ref(false);
const loadingLocalFile = ref(false);

// ========== Cornerstone3D 初始化 ==========
const {
  facade,
  isInitialized,
  isInitializing,
  initialize,
} = useCornerstone3D(false); // 不自动初始化

// ========== 视口管理（本地实现）==========
const currentImageIndex = ref(0);
const totalImages = ref(0);
const windowLevel = ref<{ windowWidth: number; windowCenter: number } | null>(null);
const viewportCreated = ref(false);

// ========== 工具管理 ==========
const {
  activeTool,
  createToolGroup,
  registerTools,
  activateTool,
  clearAllAnnotations,
} = useTools(facade);

// ========== DICOMweb 管理 ==========
const {
  studies,
  isLoading: isDicomLoading,
  isConfigured: isDicomConfigured,
  error: dicomError,
  queryStudies,
  loadSeriesImageIds,
} = useDICOMweb(facade);

// ========== 标注管理 ==========
const {
  annotations,
  selectedAnnotations,
  deleteAnnotation,
  exportAnnotations,
} = useAnnotations(facade);

// ========== 本地状态 ==========
const currentImageIds = ref<string[]>([]);

/**
 * 创建视口
 */
const createViewport = async () => {
  if (!facade.value || !viewportElement.value) {
    throw new Error('Facade 或视口元素未准备好');
  }

  if (viewportCreated.value) {
    console.log('[IntegratedViewer] 视口已存在，跳过创建');
    return;
  }

  try {
    console.log('[IntegratedViewer] 🏗️ 开始创建渲染引擎和视口...');
    console.log('[IntegratedViewer] 📍 视口元素:', viewportElement.value);
    console.log('[IntegratedViewer] 📍 引擎ID:', currentRenderingEngineId.value);
    console.log('[IntegratedViewer] 📍 视口ID:', currentViewportId.value);
    
    // 创建渲染引擎
    const engine = facade.value.createRenderingEngine(currentRenderingEngineId.value);
    console.log('[IntegratedViewer] ✅ 渲染引擎创建成功:', engine);
    
    // 创建 Stack 视口（不传入 imageIds，稍后加载）
    console.log('[IntegratedViewer] 🔄 创建Stack视口...');
    const viewport = await facade.value.createStackViewport({
      engineId: currentRenderingEngineId.value,
      viewportId: currentViewportId.value,
      element: viewportElement.value,
      imageIds: [], // 空数组，稍后通过 setStack 加载
    });
    console.log('[IntegratedViewer] ✅ Stack视口创建成功:', viewport);

    viewportCreated.value = true;
    console.log('[IntegratedViewer] ✅✅ 视口创建完全成功！');

    // 创建工具组
    console.log('[IntegratedViewer] 🔧 创建工具组...');
    await createToolGroup({
      toolGroupId: 'main-tool-group',
      viewportIds: [currentViewportId.value],
    });
    console.log('[IntegratedViewer] ✅ 工具组创建成功');

    // 注册常用工具
    console.log('[IntegratedViewer] 🔧 注册工具...');
    await registerTools([
      'WindowLevel',
      'Pan',
      'Zoom',
      'StackScroll',
      'Length',
      'Angle',
      'RectangleROI',
      'EllipticalROI',
    ]);
    console.log('[IntegratedViewer] ✅ 工具注册成功');

    // 激活默认工具
    console.log('[IntegratedViewer] 🔧 激活默认工具...');
    try {
      await activateTool({
        toolName: 'WindowLevel',
        mode: 'Active',
      });
      console.log('[IntegratedViewer] ✅ 默认工具激活成功');
    } catch (toolError: any) {
      console.warn('[IntegratedViewer] ⚠️ 工具激活失败:', toolError.message);
      // 工具激活失败不应该阻止视口创建
    }

    console.log('[IntegratedViewer] ✅✅ 工具初始化完成');
  } catch (error: any) {
    console.error('[IntegratedViewer] 创建视口失败:', error);
    throw error;
  }
};

/**
 * 加载图像到视口
 */
const loadImagesToViewport = async (imageIds: string[]) => {
  if (!facade.value || !viewportCreated.value) {
    throw new Error('视口未创建');
  }

  try {
    console.log('[IntegratedViewer] 📥 加载图像到视口...', imageIds);
    console.log('[IntegratedViewer] 🔍 视口ID:', currentViewportId.value);
    console.log('[IntegratedViewer] 🔍 引擎ID:', currentRenderingEngineId.value);

    // 获取渲染引擎
    const renderingEngine = facade.value.getRenderingEngine(currentRenderingEngineId.value);
    if (!renderingEngine) {
      throw new Error('无法获取渲染引擎');
    }
    console.log('[IntegratedViewer] ✅ 渲染引擎获取成功');

    // 获取视口
    const viewport = facade.value.getViewport(currentRenderingEngineId.value, currentViewportId.value);
    if (!viewport) {
      throw new Error('无法获取视口');
    }
    console.log('[IntegratedViewer] ✅ 视口获取成功, 类型:', viewport.type);

    // 使用 setStack 加载图像
    console.log('[IntegratedViewer] 🔄 准备调用 setStack...');
    console.log('[IntegratedViewer] 📍 viewport 对象:', viewport);
    console.log('[IntegratedViewer] 📍 viewport.setStack 方法存在:', typeof viewport.setStack);
    console.log('[IntegratedViewer] 📍 要加载的 imageIds:', imageIds);
    console.log('[IntegratedViewer] 📍 imageIds 长度:', imageIds.length);
    console.log('[IntegratedViewer] 📍 起始索引:', 0);
    
    try {
      console.log('[IntegratedViewer] 🔄 正在调用 viewport.setStack(imageIds, 0)...');
      const setStackResult = await viewport.setStack(imageIds, 0);
      console.log('[IntegratedViewer] ✅ setStack 调用返回:', setStackResult);
      console.log('[IntegratedViewer] ✅ setStack 完成');
    } catch (setStackError: any) {
      console.error('[IntegratedViewer] ❌ setStack 调用失败');
      console.error('[IntegratedViewer] ❌ 错误对象:', setStackError);
      console.error('[IntegratedViewer] ❌ 错误类型:', setStackError?.constructor?.name);
      console.error('[IntegratedViewer] ❌ 错误消息:', setStackError?.message);
      console.error('[IntegratedViewer] ❌ 错误堆栈:', setStackError?.stack);
      throw setStackError;
    }
    
    // 渲染视口
    console.log('[IntegratedViewer] 🎨 开始渲染...');
    viewport.render();
    console.log('[IntegratedViewer] ✅ 渲染完成');

    // 强制刷新渲染引擎
    renderingEngine.render();
    console.log('[IntegratedViewer] ✅ 引擎渲染完成');

    totalImages.value = imageIds.length;
    currentImageIndex.value = 0;

    console.log('[IntegratedViewer] ✅✅✅ 图像加载完全成功！');
  } catch (error: any) {
    console.error('[IntegratedViewer] ❌ 加载图像失败:', error);
    console.error('[IntegratedViewer] ❌ 错误堆栈:', error.stack);
    throw error;
  }
};

/**
 * 测试 Orthanc 连接
 */
const testOrthancConnection = async () => {
  try {
    const connected = await orthancService.testConnection();
    orthancConnected.value = connected;
    
    if (connected) {
      console.log('[IntegratedViewer] Orthanc 连接成功');
    } else {
      console.warn('[IntegratedViewer] Orthanc 连接失败');
    }
    
    return connected;
  } catch (error) {
    console.error('[IntegratedViewer] Orthanc 连接测试失败:', error);
    orthancConnected.value = false;
    return false;
  }
};

/**
 * 格式化日期
 */
const formatDate = (dateStr?: string): string => {
  if (!dateStr) return 'N/A';
  
  // DICOM 日期格式: YYYYMMDD
  if (dateStr.length === 8) {
    const year = dateStr.substring(0, 4);
    const month = dateStr.substring(4, 6);
    const day = dateStr.substring(6, 8);
    return `${year}-${month}-${day}`;
  }
  
  return dateStr;
};

/**
 * 刷新实例列表（优化版，参考 DicomStaticView）
 */
const refreshInstanceList = async () => {
  if (!orthancConnected.value) {
    $q.notify({
      type: 'warning',
      message: 'Orthanc 未连接',
      position: 'top',
    });
    return;
  }

  loadingInstances.value = true;
  
  try {
    console.log('[IntegratedViewer] 🔄 刷新Orthanc实例列表...');
    console.time('[IntegratedViewer] ⏱️ 实例列表加载耗时');
    
    // 获取所有研究
    const studies = await orthancService.getStudies();
    console.log(`[IntegratedViewer] 找到 ${studies.length} 个研究`);
    
    // 并发处理所有研究
    const studyPromises = studies.map(async (study) => {
      const patientName = study.PatientMainDicomTags?.PatientName || study.MainDicomTags?.PatientName || '未知患者';
      const studyDescription = study.MainDicomTags?.StudyDescription || '无描述';
      const studyDate = study.MainDicomTags?.StudyDate || '';
      
      const studyLabel = `${patientName} - ${studyDescription} (${formatDate(studyDate)})`;
      
      // 并发获取研究中的所有系列
      const seriesPromises = (study.Series || []).map(async (seriesId: string) => {
        try {
          const seriesResponse = await fetch(`/api/orthanc/series/${seriesId}`);
          const seriesData = await seriesResponse.json();
          
          const seriesDescription = seriesData.MainDicomTags?.SeriesDescription || '无描述';
          const modality = seriesData.MainDicomTags?.Modality || 'Unknown';
          
          // 获取系列中的所有实例
          const instanceCount = seriesData.Instances?.length || 0;
          
          const seriesInstances = [];
          for (let i = 0; i < instanceCount; i++) {
            const instanceId = seriesData.Instances[i];
            
            const instanceLabel = `${seriesDescription} - ${modality} - 实例 ${i + 1}`;
            
            const instance = {
              id: instanceId,
              label: instanceLabel,
              sopInstanceUID: null,
              studyInstanceUID: study.MainDicomTags?.StudyInstanceUID,
              seriesInstanceUID: seriesData.MainDicomTags?.SeriesInstanceUID,
              patientName,
              studyDescription,
              seriesDescription,
              modality,
              instanceNumber: i + 1,
              detailsLoaded: false
            };
            
            seriesInstances.push(instance);
          }
          
          return seriesInstances;
        } catch (error) {
          console.warn(`[IntegratedViewer] 获取系列失败: ${seriesId}`);
          return [];
        }
      });
      
      // 等待所有系列加载完成
      const allSeriesInstances = await Promise.all(seriesPromises);
      const studyInstances = allSeriesInstances.flat();
      
      return {
        studyData: {
          id: study.ID,
          label: studyLabel,
          instances: studyInstances
        },
        instances: studyInstances
      };
    });
    
    // 等待所有研究加载完成
    const allStudiesResults = await Promise.all(studyPromises);
    
    // 提取结果
    const studyTree = allStudiesResults.map(result => result.studyData);
    const allInstances = allStudiesResults.flatMap(result => result.instances);
    
    availableStudies.value = studyTree;
    availableInstances.value = allInstances;
    
    console.timeEnd('[IntegratedViewer] ⏱️ 实例列表加载耗时');
    console.log(`[IntegratedViewer] ✅ 实例列表刷新完成,共 ${allInstances.length} 个实例`);
    
    $q.notify({
      type: 'positive',
      message: `找到 ${allInstances.length} 个DICOM实例`,
      position: 'top',
    });
  } catch (error: any) {
    console.error('[IntegratedViewer] 刷新实例列表失败:', error);
    $q.notify({
      type: 'negative',
      message: `刷新实例列表失败: ${error.message}`,
      position: 'top',
    });
  } finally {
    loadingInstances.value = false;
  }
};

/**
 * 实例选择框点击事件
 */
const onInstanceSelectClick = async () => {
  // 如果还没有加载实例列表，则自动刷新
  if (orthancConnected.value && availableInstances.value.length === 0 && !loadingInstances.value) {
    console.log('[IntegratedViewer] 🔄 首次点击下拉框，自动刷新实例列表...');
    await refreshInstanceList();
  }
};

/**
 * 按需获取实例详细信息
 */
const loadInstanceDetails = async (instanceId: string) => {
  try {
    const instanceResponse = await fetch(`/api/orthanc/instances/${instanceId}`);
    const instanceData = await instanceResponse.json();
    
    return {
      instanceNumber: instanceData.MainDicomTags?.InstanceNumber || '1',
      sopInstanceUID: instanceData.MainDicomTags?.SOPInstanceUID || instanceId
    };
  } catch (error) {
    console.warn(`[IntegratedViewer] 获取实例详细信息失败: ${instanceId}`);
    return {
      instanceNumber: '1',
      sopInstanceUID: instanceId
    };
  }
};

/**
 * 加载选中的实例（优化版，参考 DicomStaticView）
 */
const loadSelectedInstance = async () => {
  if (!selectedInstanceId.value) {
    $q.notify({
      type: 'warning',
      message: '请先选择一个DICOM实例',
      position: 'top',
    });
    return;
  }

  loadingImage.value = true;
  
  try {
    console.time('[IntegratedViewer] ⏱️ 实例加载耗时');
    
    // 找到选中的实例信息
    const selectedInstance = availableInstances.value.find(
      instance => instance.id === selectedInstanceId.value
    );
    
    if (!selectedInstance) {
      throw new Error('未找到选中的实例');
    }
    
    console.log('[IntegratedViewer] 🚀 正在加载选中的DICOM实例...', selectedInstance);
    
    // 并发：同时加载图像和详细信息
    const loadPromises: Promise<any>[] = [
      orthancService.getDicomImageByInstanceId(selectedInstanceId.value)
    ];
    
    // 如果实例详细信息未加载，并发获取
    let detailsPromise: Promise<any> | null = null;
    if (!selectedInstance.detailsLoaded) {
      console.log('[IntegratedViewer] 📥 并发获取实例详细信息...');
      detailsPromise = loadInstanceDetails(selectedInstance.id);
      loadPromises.push(detailsPromise);
    }
    
    // 等待所有并发请求完成
    const results = await Promise.all(loadPromises);
    const imageBlob = results[0];
    
    // 如果获取了详细信息，更新实例
    if (detailsPromise) {
      const details = results[1];
      selectedInstance.sopInstanceUID = details.sopInstanceUID;
      selectedInstance.instanceNumber = details.instanceNumber;
      selectedInstance.detailsLoaded = true;
    }
    
    // 创建图像URL
    const imageUrl = URL.createObjectURL(imageBlob);
    console.log('[IntegratedViewer] 📸 图像Blob创建成功，大小:', (imageBlob.size / 1024).toFixed(2), 'KB');
    console.log('[IntegratedViewer] 📸 图像类型:', imageBlob.type);
    
    // 检查 Blob 类型，决定加载方式
    let imageId: string;
    
    // Orthanc 的 preview 端点返回的是 JPEG/PNG，不是 DICOM
    // 我们需要使用 web 协议而不是 wadouri
    if (imageBlob.type.includes('image/')) {
      // 这是一个普通图像（JPEG/PNG）
      console.log('[IntegratedViewer] ⚠️ 检测到预览图像格式，将直接显示');
      
      // 对于预览图像，我们需要用不同的方式处理
      // 暂时先显示在 img 元素中，而不是通过 Cornerstone
      const img = new Image();
      img.src = imageUrl;
      
      // 清空视口并添加图片
      if (viewportElement.value) {
        viewportElement.value.innerHTML = '';
        img.style.width = '100%';
        img.style.height = '100%';
        img.style.objectFit = 'contain';
        viewportElement.value.appendChild(img);
      }
      
      currentImageIds.value = [imageUrl];
      totalImages.value = 1;
      
      $q.notify({
        type: 'info',
        message: '已加载预览图像（非DICOM格式）',
        position: 'top',
      });
      
      return;
    } else {
      // 尝试作为 DICOM 文件加载
      imageId = `wadouri:${imageUrl}`;
      currentImageIds.value = [imageId];

      // 如果视口未创建，先创建视口
      if (!viewportCreated.value) {
        await createViewport();
      }

      // 加载图像到视口
      await loadImagesToViewport([imageId]);
    }
    
    console.timeEnd('[IntegratedViewer] ⏱️ 实例加载耗时');
    console.log('[IntegratedViewer] ✅ 图像加载成功');
    
    $q.notify({
      type: 'positive',
      message: `图像加载成功: ${selectedInstance.label}`,
      position: 'top',
    });
  } catch (error: any) {
    console.error('[IntegratedViewer] 加载实例失败:', error);
    $q.notify({
      type: 'negative',
      message: `加载实例失败: ${error.message}`,
      position: 'top',
    });
  } finally {
    loadingImage.value = false;
  }
};

/**
 * 触发文件选择
 */
const triggerFileSelect = () => {
  fileInput.value?.click();
};

/**
 * 处理文件选择
 */
const handleFileSelect = async (event: Event) => {
  const target = event.target as HTMLInputElement;
  const file = target.files?.[0];
  
  if (!file) {
    return;
  }

  loadingLocalFile.value = true;

  try {
    console.log('[IntegratedViewer] 📁 开始加载本地文件:', file.name);
    console.log('[IntegratedViewer] 📁 文件大小:', (file.size / 1024).toFixed(2), 'KB');
    console.log('[IntegratedViewer] 📁 文件类型:', file.type);
    console.time('[IntegratedViewer] ⏱️ 本地文件加载耗时');

    // 使用 facade 的 loadImagesFromFiles 方法
    if (!facade.value) {
      throw new Error('Cornerstone3D 未初始化');
    }

    // 加载文件并获取 imageIds
    console.log('[IntegratedViewer] 🔄 调用 loadImagesFromFiles...');
    const imageIds = await facade.value.loadImagesFromFiles([file]);
    console.log('[IntegratedViewer] ✅ loadImagesFromFiles 返回 imageIds:', imageIds);
    console.log('[IntegratedViewer] 📍 imageIds 数量:', imageIds.length);
    console.log('[IntegratedViewer] 📍 第一个 imageId:', imageIds[0]);

    if (imageIds.length === 0) {
      throw new Error('无法从文件中提取图像');
    }

    currentImageIds.value = imageIds;

    // 如果视口未创建，先创建视口
    if (!viewportCreated.value) {
      console.log('[IntegratedViewer] 🏗️ 视口未创建，开始创建视口...');
      await createViewport();
      console.log('[IntegratedViewer] ✅ 视口创建完成');
    }

    // 加载图像到视口
    console.log('[IntegratedViewer] 📥 开始加载图像到视口...');
    await loadImagesToViewport(imageIds);
    console.log('[IntegratedViewer] ✅ 图像已加载到视口');

    console.timeEnd('[IntegratedViewer] ⏱️ 本地文件加载耗时');
    
    $q.notify({
      type: 'positive',
      message: `本地文件加载成功: ${file.name}`,
      position: 'top',
    });

    console.log('[IntegratedViewer] ✅✅ 本地DICOM文件加载完全成功');
  } catch (error: any) {
    console.error('[IntegratedViewer] ❌ 加载本地文件失败:', error);
    console.error('[IntegratedViewer] ❌ 错误类型:', error.constructor.name);
    console.error('[IntegratedViewer] ❌ 错误消息:', error.message);
    console.error('[IntegratedViewer] ❌ 错误堆栈:', error.stack);
    $q.notify({
      type: 'negative',
      message: `加载本地文件失败: ${error.message}`,
      position: 'top',
    });
  } finally {
    loadingLocalFile.value = false;
    // 清空 input，以便可以重复选择同一个文件
    if (target) {
      target.value = '';
    }
  }
};

/**
 * 加载预设示例图像
 */
const loadExampleFromOrthanc = async () => {
  loadingExample.value = true;
  
  try {
    console.log('[IntegratedViewer] 加载预设示例图像...');
    
    // 验证实例是否存在
    const instanceExists = await orthancService.verifyInstanceExists(exampleDicomInstance);
    if (!instanceExists) {
      throw new Error('示例DICOM实例不存在,请检查配置或选择其他实例');
    }
    
    // 获取图像
    const imageBlob = await orthancService.getDicomImage(exampleDicomInstance);
    
    // 创建图像URL
    const imageUrl = URL.createObjectURL(imageBlob);
    console.log('[IntegratedViewer] 📸 示例图像类型:', imageBlob.type);
    
    // 检查图像类型
    if (imageBlob.type.includes('image/')) {
      // 普通图像格式
      console.log('[IntegratedViewer] ⚠️ 检测到预览图像格式，将直接显示');
      
      const img = new Image();
      img.src = imageUrl;
      
      if (viewportElement.value) {
        viewportElement.value.innerHTML = '';
        img.style.width = '100%';
        img.style.height = '100%';
        img.style.objectFit = 'contain';
        viewportElement.value.appendChild(img);
      }
      
      currentImageIds.value = [imageUrl];
      totalImages.value = 1;
      
      $q.notify({
        type: 'info',
        message: '已加载示例预览图像（非DICOM格式）',
        position: 'top',
      });
      
      return;
    } else {
      // DICOM 文件
      const imageId = `wadouri:${imageUrl}`;
      currentImageIds.value = [imageId];

      // 如果视口未创建，先创建视口
      if (!viewportCreated.value) {
        await createViewport();
      }

      // 加载图像到视口
      await loadImagesToViewport([imageId]);
    }
    
    $q.notify({
      type: 'positive',
      message: '示例图像加载成功',
      position: 'top',
    });
  } catch (error: any) {
    console.error('[IntegratedViewer] 加载示例图像失败:', error);
    $q.notify({
      type: 'negative',
      message: `加载示例图像失败: ${error.message}`,
      position: 'top',
    });
  } finally {
    loadingExample.value = false;
  }
};

/**
 * 初始化应用
 */
const handleInitialize = async () => {
  try {
    // 1. 初始化 Cornerstone3D
    await initialize({
      maxCacheSize: 512,
      useGPURendering: true,
      enablePerformanceMonitor: false,
    });

    $q.notify({
      type: 'positive',
      message: 'Cornerstone3D 初始化成功',
      position: 'top',
    });

    // 2. 测试 Orthanc 连接
    const connected = await testOrthancConnection();
    
    if (connected) {
      $q.notify({
        type: 'positive',
        message: 'Orthanc 连接成功',
        position: 'top',
      });
      
      // 3. 刷新实例列表
      await refreshInstanceList();
    } else {
      $q.notify({
        type: 'warning',
        message: 'Orthanc 连接失败,但可以继续使用本地文件',
        position: 'top',
      });
    }

  } catch (err: any) {
    console.error('[IntegratedViewer] 初始化失败:', err);
    $q.notify({
      type: 'negative',
      message: `初始化失败: ${err.message}`,
      position: 'top',
    });
  }
};


/**
 * 处理工具选择
 */
const handleToolSelect = async (toolName: string) => {
  try {
    await activateTool({
      toolName,
      mode: 'Active',
    });
  } catch (err: any) {
    $q.notify({
      type: 'negative',
      message: `激活工具失败: ${err.message}`,
      position: 'top',
    });
  }
};

/**
 * 处理重置
 */
const handleReset = () => {
  if (facade.value && viewportCreated.value) {
    const viewport = facade.value.getViewport(currentRenderingEngineId.value, currentViewportId.value);
    if (viewport) {
      viewport.resetCamera();
      viewport.render();
    }
  }
};

/**
 * 处理清除标注
 */
const handleClearAnnotations = async () => {
  try {
    await clearAllAnnotations();
    $q.notify({
      type: 'positive',
      message: '标注已清除',
      position: 'top',
    });
  } catch (err: any) {
    $q.notify({
      type: 'negative',
      message: `清除标注失败: ${err.message}`,
      position: 'top',
    });
  }
};

/**
 * 处理导出标注
 */
const handleExportAnnotations = async () => {
  try {
    const data = await exportAnnotations('json');
    
    // 创建下载链接
    const blob = new Blob([data], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `annotations-${Date.now()}.json`;
    a.click();
    URL.revokeObjectURL(url);

    $q.notify({
      type: 'positive',
      message: '标注已导出',
      position: 'top',
    });
  } catch (err: any) {
    $q.notify({
      type: 'negative',
      message: `导出标注失败: ${err.message}`,
      position: 'top',
    });
  }
};

/**
 * 处理查询 Studies
 */
const handleSearchStudies = async (params: any) => {
  try {
    await queryStudies(params);
  } catch (err: any) {
    $q.notify({
      type: 'negative',
      message: `查询失败: ${err.message}`,
      position: 'top',
    });
  }
};

/**
 * 处理加载 Study
 */
const handleLoadStudy = async (study: StudyInfo) => {
  try {
    $q.loading.show({
      message: '加载图像中...',
    });

    // 这里需要先查询 Series,然后加载图像
    // 简化示例:假设已经有了 seriesInstanceUID
    const seriesInstanceUID = 'example-series-uid'; // 实际应该从 querySeries 获取
    
    const imageIds = await loadSeriesImageIds(
      study.studyInstanceUID,
      seriesInstanceUID
    );

    currentImageIds.value = imageIds;

    $q.notify({
      type: 'positive',
      message: `加载了 ${imageIds.length} 张图像`,
      position: 'top',
    });
  } catch (err: any) {
    $q.notify({
      type: 'negative',
      message: `加载图像失败: ${err.message}`,
      position: 'top',
    });
  } finally {
    $q.loading.hide();
  }
};

/**
 * 图像导航
 */
const handleImageNavigate = (index: number) => {
  if (facade.value && viewportCreated.value && currentImageIds.value.length > 0) {
    const viewport = facade.value.getViewport(currentRenderingEngineId.value, currentViewportId.value);
    if (viewport) {
      viewport.setImageIdIndex(index);
      viewport.render();
      currentImageIndex.value = index;
    }
  }
};

const handleImageFirst = () => {
  handleImageNavigate(0);
};

const handleImagePrevious = () => {
  if (currentImageIndex.value > 0) {
    handleImageNavigate(currentImageIndex.value - 1);
  }
};

const handleImageNext = () => {
  if (currentImageIndex.value < totalImages.value - 1) {
    handleImageNavigate(currentImageIndex.value + 1);
  }
};

const handleImageLast = () => {
  if (totalImages.value > 0) {
    handleImageNavigate(totalImages.value - 1);
  }
};

/**
 * 标注操作
 */
const handleSelectAnnotation = (annotationUID: string) => {
  console.log('[IntegratedViewer] 选择标注:', annotationUID);
};

const handleDeleteAnnotation = async (annotationUID: string) => {
  try {
    await deleteAnnotation(annotationUID);
    $q.notify({
      type: 'positive',
      message: '标注已删除',
      position: 'top',
    });
  } catch (err: any) {
    $q.notify({
      type: 'negative',
      message: `删除标注失败: ${err.message}`,
      position: 'top',
    });
  }
};

// 组件挂载时测试 Orthanc 连接
onMounted(async () => {
  await testOrthancConnection();
});
</script>

<style scoped lang="scss">
.integrated-viewer {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background-color: #f5f5f5;
}

.top-toolbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 24px;
  background-color: #fff;
  border-bottom: 1px solid #e0e0e0;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

  .toolbar-left {
    display: flex;
    align-items: center;
    gap: 16px;
  }

  .toolbar-right {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-left: auto;
  }

  .page-title {
    margin: 0;
    font-size: 20px;
    font-weight: 500;
    color: #333;
  }

  .connection-status {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    background: #f8f9fa;
    border-radius: 4px;
    font-size: 13px;

    .status-indicator {
      font-size: 14px;
      
      &.connected {
        animation: pulse 2s ease-in-out infinite;
      }
    }

    .status-text {
      color: #666;
      font-weight: 500;
    }
  }

  .instance-select {
    padding: 8px 12px;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    font-size: 13px;
    background: white;
    cursor: pointer;
    min-width: 200px;
    max-width: 300px;

    &:focus {
      outline: none;
      border-color: #1976d2;
    }

    &:disabled {
      background: #f5f5f5;
      cursor: not-allowed;
    }
  }
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}

.main-content {
  display: flex;
  flex: 1;
  gap: 16px;
  padding: 16px;
  overflow: hidden;
}

.left-panel {
  width: 400px;
  display: flex;
  flex-direction: column;
  background-color: #fff;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

.center-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 16px;
  overflow: hidden;
}

.right-panel {
  width: 350px;
  background-color: #fff;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

/* DICOM 视口 */
.dicom-viewport {
  flex: 1;
  background: #000;
  border-radius: 4px;
  overflow: hidden;
  position: relative;
  min-height: 400px;

  &.has-image {
    background: #000;
  }
}

.empty-viewport {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  color: #666;
}

.empty-icon {
  font-size: 64px;
  margin-bottom: 16px;
  opacity: 0.5;
}

.empty-text {
  font-size: 16px;
  color: #999;
}
</style>

